#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <bits/types/stack_t.h>

#ifndef RB_UNUSED_VAR
#ifdef __GNUC__
#define RB_UNUSED_VAR(x) x __attribute__((unused))
#else
#define RB_UNUSED_VAR(x) x
#endif
#endif

int ruby_disable_gc = 0;
#if defined SIGSEGV || defined SIGBUS || defined SIGILL || defined SIGFPE
static const char *received_signal;
#define clear_received_signal() (void)(ruby_disable_gc = 0, received_signal = 0)
#else
#define clear_received_signal() ((void)0)
#endif

#ifdef InterlockedExchangePointer
#define RUBY_ATOMIC_PTR_EXCHANGE(var, val) InterlockedExchangePointer((PVOID volatile *)&(var), (PVOID)(val))
#endif /* See below for definitions of other situations */
#define RUBY_ATOMIC_EXCHANGE(var, val) __atomic_exchange_n(&(var), (val), __ATOMIC_SEQ_CST)

#ifndef RUBY_ATOMIC_PTR_EXCHANGE
#define RUBY_ATOMIC_PTR_EXCHANGE(var, val) RUBY_ATOMIC_EXCHANGE(var, val)
#endif
#define ATOMIC_PTR_EXCHANGE(var, val) RUBY_ATOMIC_PTR_EXCHANGE(var, val)
 
#ifdef USE_SIGALTSTACK
typedef void ruby_sigaction_t(int, siginfo_t*, void*);
#define SIGINFO_ARG , siginfo_t *info, void *ctx
#define SIGINFO_CTX ctx
#else
#define SIGINFO_ARG
#define SIGINFO_CTX 0
#endif
 

static void check_reserved_signal_(const char *name, size_t name_len)
{
    const char *prev = ATOMIC_PTR_EXCHANGE(received_signal, name);

    if (prev)
    {
        ssize_t RB_UNUSED_VAR(err);
#define NOZ(name, str) name[sizeof(str)] = str
        static const char NOZ(msg1, " received in ");
        static const char NOZ(msg2, " handler\n");

#ifdef HAVE_WRITEV
        struct iovec iov[4];

        iov[0].iov_base = (void *)name;
        iov[0].iov_len = name_len;
        iov[1].iov_base = (void *)msg1;
        iov[1].iov_len = sizeof(msg1);
        iov[2].iov_base = (void *)prev;
        iov[2].iov_len = strlen(prev);
        iov[3].iov_base = (void *)msg2;
        iov[3].iov_len = sizeof(msg2);
        err = writev(2, iov, 4);
#else
        err = write(2, name, name_len);
        err = write(2, msg1, sizeof(msg1));
        err = write(2, prev, strlen(prev));
        err = write(2, msg2, sizeof(msg2));
#endif
    }
    printf("over\n");
    exit(-1);
}
#define check_reserved_signal(name) check_reserved_signal_(name, sizeof(name)-1)
static void sigsegv(int sig SIGINFO_ARG)
{
    check_reserved_signal("SEGV");
    // CHECK_STACK_OVERFLOW();
    // rb_bug_for_fatal_signal(default_sigsegv_handler, sig, SIGINFO_CTX, "Segmentation fault" MESSAGE_FAULT_ADDRESS);
}
/** 信号处理函数 */
void sig_handler(int sig)
{
    switch (sig)
    {
    case SIGSEGV:
        sigsegv(sig);
        break;
    default:
        ;
        break;
    }
}

/** 栈溢出测试 */
unsigned stackOver(unsigned x){return stackOver(x) + 1;}
/** 备用栈注册 */
static void register_sigaltstack()
{
    static int is_altstack_defined = 0;
    stack_t newSS, oldSS;
    if (is_altstack_defined)
        return;

    newSS.ss_sp = malloc(SIGSTKSZ);
    if (!newSS.ss_sp)
    {
        perror("in register_sigaltstack() malloc():");
        return;
    }
    newSS.ss_size = SIGSTKSZ;
    newSS.ss_flags = 0;
    if (sigaltstack(&newSS, &oldSS) == -1)
    {
        perror("in register_sigaltstack()  sigaltstack():");
        return;
    }
    is_altstack_defined = 1;
}
/** 信号处理函数 */
static sighandler_t ruby_signal(int signum, sighandler_t handler)
{
    static struct sigaction sigact, old;
    if (signum == SIGCHLD && handler == SIG_IGN)
        sigact.sa_flags |= SA_NOCLDWAIT;
    if (signum == SIGSEGV)
        sigact.sa_flags |= SA_ONSTACK;

    sigact.sa_handler = handler; /* Address of a signal handler */
    if (sigaction(signum, &sigact, &old) < 0)
        perror("in ruby_signal() sigaction()");

    return old.sa_handler;
}
int main(int argc, char *argv[])
{
    register_sigaltstack();
    ruby_signal(SIGSEGV, sig_handler);
    stackOver(0);
    return 0;
}